package com.boby.homecamera.service.server

import android.content.Context
import android.media.MediaCodec
import android.media.MediaFormat
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import com.boby.homecamera.config.AppConfig
import com.boby.homecamera.constant.Constant
import com.boby.homecamera.helper.AudioDetectHelper
import com.boby.homecamera.helper.VideoDetectHelper
import com.boby.homecamera.helper.WriteRecordFileHelper
import com.boby.homecamera.util.JwtUtil.validateToken
import com.boby.homecamera.yolo.YOLO11Ncnn
import com.pedro.common.AudioCodec
import com.pedro.common.ConnectChecker
import com.pedro.common.VideoCodec
import com.pedro.encoder.Frame
import com.pedro.encoder.input.gl.render.filters.MultiBoxBorderFilterRender
import com.pedro.library.base.Camera2Base2
import com.pedro.rtspserver.server.ClientListener
import com.pedro.rtspserver.server.RtspServer
import com.pedro.rtspserver.server.ServerClient
import java.nio.ByteBuffer
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi


class RecordServer(context: Context?) : Camera2Base2(context) {
    companion object{
        private val TAG = "RecordServer"
    }
    private var writeRecordFileHelper : WriteRecordFileHelper? = null

    private var audioFormat: MediaFormat? = null
    private var videoFormat: MediaFormat? = null
    private var rtspServer:RtspServer? = null
    private var audioDetectHelper : AudioDetectHelper? = null
    private var videoDetectHelper : VideoDetectHelper? = null

    fun start() {

        initRtsp()
        initPersonDetect(context)
        if(AppConfig.isDetectAudioEvent == true){
            audioDetectHelper = AudioDetectHelper()
            audioDetectHelper?.start()
        }

        setCameraVerticalFlip(AppConfig.isFlipVertical!!)
        setCameraHorizontalFlip(AppConfig.isFlipHorizontal!!)
        setCameraId("${AppConfig.videoCameraId}")
        val prepare = prepare()
        if(!prepare){
            Log.d(TAG, "prepare fail")
            return
        }
        startStream("")
    }

    @Synchronized
    fun stop() {
        stopStream()
        writeRecordFileHelper?.stop()
        writeRecordFileHelper = null
        audioDetectHelper?.release()
        audioDetectHelper = null
        videoDetectHelper?.release()
        videoDetectHelper = null
    }

    private fun prepare():Boolean{
      setCaptureSize(AppConfig.Record.CAPTURE_WIDTH, AppConfig.Record.CAPTURE_HEIGHT)
      return  prepareAudio(
          AppConfig.Record.RECORD_AUDIO_BITRATE,
          AppConfig.Record.RECORD_AUDIO_SAMPLE_RATE,false,true,true)
              &&
              prepareVideo(
          AppConfig.Record.RECORD_VIDEO_WIDTH,
          AppConfig.Record.RECORD_VIDEO_HEIGHT,
          AppConfig.Record.RECORD_VIDEO_FPS,
          AppConfig.Record.RECORD_VIDEO_BITRATE,0)
    }

    @Synchronized
    private  fun initRecord(){
        if(audioFormat == null || videoFormat == null){
            return
        }
        writeRecordFileHelper = WriteRecordFileHelper(audioFormat!!, videoFormat!!)
        writeRecordFileHelper?.videoWidth = AppConfig.Record.RECORD_VIDEO_WIDTH
        writeRecordFileHelper?.videoHeight = AppConfig.Record.RECORD_VIDEO_HEIGHT
        writeRecordFileHelper?.start()
        Log.d(TAG, "initRecord")
    }

    override fun onAudioInfoImp(isStereo: Boolean, sampleRate: Int) {
        rtspServer?.setAudioInfo(sampleRate, isStereo)
    }

    override fun startStreamImp(url: String?) {
        rtspServer?.startServer()
    }

    override fun stopStreamImp() {
        rtspServer?.stopServer()
    }

    override fun getAudioDataImp(audioBuffer: ByteBuffer, info: MediaCodec.BufferInfo) {
        //保存录音数据到文件、或者发送到rtsp
        rtspServer?.sendAudio(audioBuffer, info)
        writeRecordFileHelper?.writeAudio(audioBuffer,info)
    }

    override fun onPcm(frame: Frame) {
        val bytes = ByteArray(frame.size)
        System.arraycopy(frame.buffer, frame.offset, bytes, 0, frame.size)
        audioDetectHelper?.onPcm(bytes)
    }

    override fun onAudioFormatImp(mediaFormat: MediaFormat) {
        audioFormat = mediaFormat
        initRecord()

    }

    override fun onVideoFormatImp(mediaFormat: MediaFormat) {
        videoFormat = mediaFormat
        initRecord()
    }

    override fun onVideoInfoImp(sps: ByteBuffer, pps: ByteBuffer?, vps: ByteBuffer?) {
        rtspServer?.setVideoInfo(sps, pps, vps)
    }

    override fun getVideoDataImp(videoBuffer: ByteBuffer, info: MediaCodec.BufferInfo) {
        //保存录音数据到文件、或者发送到rtsp
        writeRecordFileHelper?.writeVideo(videoBuffer, info)
        rtspServer?.sendVideo(videoBuffer, info)
    }


    override fun setVideoCodecImp(codec: VideoCodec?) {
        rtspServer?.setVideoCodec(codec!!)
    }

    override fun setAudioCodecImp(codec: AudioCodec?) {
        rtspServer?.setAudioCodec(codec!!)
    }

    @OptIn(ExperimentalEncodingApi::class)
    private fun initRtsp(){
       val  connectChecker = object:ConnectChecker{
            override fun onAuthError() {
                Log.d(TAG,"onAuthError")
//                rtspServerCamera1.stopStream()
            }

            override fun onAuthSuccess() {
                Log.d(TAG,"onAuthSuccess")
            }

            override fun onConnectionFailed(reason: String) {
                Log.d(TAG,"onConnectionFailed $reason")
//                rtspServerCamera1.stopStream()
            }

            override fun onConnectionStarted(url: String) {
                Log.d(TAG,"onConnectionStarted :$url ")
            }

            override fun onConnectionSuccess() {
                Log.d(TAG,"onConnectionSuccess")
            }

            override fun onDisconnect() {
                Log.d(TAG,"onDisconnect")
            }

        }

        rtspServer = RtspServer(connectChecker, Constant.RTSP_PORT)
        rtspServer!!.setClientListener(object : ClientListener{
            override fun onClientConnected(client: ServerClient) {
                Log.d(TAG,"onClientConnected ${client.getAddress()}")
                client.setLogs(false)
            }

            override fun onClientDisconnected(client: ServerClient) {
                Log.d(TAG,"onClientDisconnected ${client.getAddress()}")
            }

            override fun onClientNewBitrate(bitrate: Long, client: ServerClient) {
//                Log.d(TAG,"onClientNewBitrate bitrate:bitrate ,${client.getAddress()}")
            }

        })
        rtspServer!!.setAuth(AppConfig.userName, AppConfig.userPassword)
        rtspServer!!.setAuthCallBack {userName,auth ->
            Log.d(TAG,"setAuthCallBack1 userName:$userName,auth:$auth")
            if(userName == AppConfig.userName){
                if(auth.isNullOrEmpty() ){
                    return@setAuthCallBack false
                }

                val authDe = String(Base64.decode(auth,0,auth.length))
                var splitIndex = authDe.indexOf(":")
                if(splitIndex > 0 && splitIndex < authDe.length){
                   val remoteUserName = authDe.substring(0,splitIndex)
                   val remoteToken = authDe.substring(splitIndex + 1,authDe.length)
                    Log.d(TAG,"setAuthCallBack2 remoteUserName:$remoteUserName,remoteToken:$remoteToken")
                    try {
                        val user = validateToken(remoteToken)
                        if(remoteUserName == AppConfig.userName && remoteUserName == user){
                            return@setAuthCallBack true
                        }
                    } catch (e: Exception) {
                        e.printStackTrace()
                        return@setAuthCallBack false
                    }
                }
                return@setAuthCallBack false
            }
            false
        }
    }

    private fun initPersonDetect(context: Context){
        if(AppConfig.isDetectPersonEvent == true){
            videoDetectHelper = VideoDetectHelper()
            videoDetectHelper?.initPersonDetect(context)
            return
        }
    }





}